// 重构了部分，原来的代码改不大动，而且功能有缺失 by songyf
import { useFormChild, useQuasar } from '@teld/q-components';
import DateComponent from '@teld/q-components/Date';
import Icon from '@teld/q-components/Icon';
import PopupProxy from '@teld/q-components/PopupProxy';
import TimeComponent from '@teld/q-components/Time';
import TmDateTimePicker from '@teld/tm-components/DateTimePicker';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import isBetween from 'dayjs/plugin/isBetween';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import useMappingProps from 't/common/hooks/useMappingProps';
import {
  commonProps,
  fixNameSpace,
  pickOwnForBasicComponent,
} from 't/common/utils';
import {
  computed,
  defineComponent,
  nextTick,
  onMounted,
  ref,
  watch,
} from 'vue';
import Button from '../button';
import Input from '../input';
import styles from './index.module.scss';
import './index.scss';

export default defineComponent({
  name: fixNameSpace('date-time'),
  props: {
    ...commonProps,
    ...DateComponent.props,
    ...TimeComponent.props,
    ...Input.props,
    confirmButtonText: {
      type: String,
      default() {
        return '';
      },
    },
    cancelButtonText: {
      type: String,
      default() {
        return '';
      },
    },
    displayFormatWithDate: {
      type: String,
      default() {
        return 'YYYY/MM/DD';
      },
    },
    displayFormatWithDateTime: {
      type: String,
      default() {
        return 'YYYY/MM/DD HH:mm:ss';
      },
    },
    displayFormatWithTime: {
      type: String,
      default() {
        return 'HH:mm:ss';
      },
    },
    dateType: {
      type: String,
      default() {
        return 'datetime';
      },
    },
    minDate: {
      type: String,
      default() {
        return '';
      },
    },
    maxDate: {
      type: String,
      default() {
        return '';
      },
    },
  },
  emits: ['update:modelValue', 'change'],

  setup(props, { attrs, emit, expose, slots }) {
    const $q = useQuasar();
    const refInput = ref();
    const refDate = ref();
    const refTime = ref();
    const refPicker = ref();
    const popupVisible = ref(false); //是否显示弹窗选择器
    const dateTime = ref('');
    const inputDateTime = ref('');
    const tmDateTime = ref('');
    dayjs.extend(customParseFormat);
    dayjs.extend(isBetween);
    dayjs.extend(isSameOrAfter);
    dayjs.extend(isSameOrBefore);

    const [mappingProps, mappingExpose] = useMappingProps(props, {
      validate() {
        return refInput.value.validate(...arguments);
      },
      resetValidation() {
        refInput.value.resetValidation(...arguments);
      },
      value: { dateValue: dateTime, inputValue: inputDateTime },
      focus() {
        refInput.value.focus(...arguments);
      },
      blur() {
        refInput.value.blur(...arguments);
      },
    });

    //与form校验绑定
    useFormChild({
      validate: function () {
        return refInput.value.validate(...arguments);
      }, // 函数；可以是异步的；
      // 应该返回一个布尔值（或一个 resolve 布尔值的 Promise）
      resetValidation: function () {
        refInput.value.resetValidation(...arguments);
      }, // 可选的函数，可重置验证
      requiresQForm: false, // 如果没有找到父级 QForm，它是否应该报错？
    });
    expose({ ...mappingExpose, popupVisible, showPopup });

    //设置默认值
    if (mappingProps.disable || mappingProps.readonly) {
      mappingProps.placeholder = '';
    }
    mappingProps.borderType = 'borderless';
    //设置格式
    const formatMap = {
      date: mappingProps.displayFormatWithDate,
      time: mappingProps.displayFormatWithTime,
      datetime: mappingProps.displayFormatWithDateTime,
    };
    let dateTimeFormat = formatMap[mappingProps.dateType];
    //掩码
    // const mask = computed(() => {
    //   return dateTimeFormat;
    // });

    //设置最小最大日期
    let optionsFn = undefined;
    let ruleFn = undefined;
    if (
      (mappingProps.minDate || mappingProps.maxDate) &&
      (mappingProps.dateType == 'date' || mappingProps.dateType == 'datetime')
    ) {
      optionsFn = checkDate;
    }

    console.log(mappingProps.dateType, 'mappingProps.dateType');
    watch(
      () => {
        return [
          mappingProps.dateType,
          mappingProps.displayFormatWithDate,
          mappingProps.displayFormatWithTime,
          mappingProps.displayFormatWithDateTime,
        ];
      },
      (newVal, oldVal) => {
        dateTimeFormat = formatMap[newVal[0]];
      },
    );
    watch(
      () => {
        return [mappingProps.minDate, mappingProps.maxDate];
      },
      (newVal, oldVal) => {
        if (
          (newVal[0] || newVal[1]) &&
          (mappingProps.dateType == 'date' ||
            mappingProps.dateType == 'datetime')
        ) {
          optionsFn = checkDate;
        } else {
          optionsFn = undefined;
        }
      },
    );
    watch(
      () => {
        return mappingProps.modelValue;
      },
      (newVal, oldVal) => {
        if (newVal != oldVal) {
          inputDateTime.value = mappingProps.modelValue
            ? calDateTime(mappingProps.modelValue)
            : '';
          if (
            typeof mappingProps.modelValue === 'object' &&
            mappingProps.modelValue !== null
          ) {
            dateTime.value = calDateTime(
              mappingProps.modelValue,
              mappingProps.dateType == 'time'
                ? 'HH:mm:ss'
                : 'YYYY/MM/DD HH:mm:ss',
            );
          } else {
            dateTime.value = mappingProps.modelValue;
          }
          //赋值时主动触发校验
          nextTick(() => {
            refInput.value.validate();
            valueUpdate(newVal);
          });
        }
      },
    );

    let mobileMinDate = computed(() => {
      let minDate = new Date();
      if (mappingProps.minDate) {
        minDate = new Date(
          dayjs(mappingProps.minDate).year(),
          dayjs(mappingProps.minDate).month(),
          dayjs(mappingProps.minDate).date(),
          0,
          0,
          0,
        );
      } else {
        minDate = new Date(dayjs().year() - 5, dayjs().month(), dayjs().date());
      }
      return minDate;
    });
    let mobileMaxDate = computed(() => {
      let maxDate = new Date();
      if (mappingProps.maxDate) {
        maxDate = new Date(
          dayjs(mappingProps.maxDate).year(),
          dayjs(mappingProps.maxDate).month(),
          dayjs(mappingProps.maxDate).date(),
        );
      } else {
        maxDate = new Date(
          dayjs().year() + 5,
          dayjs().month(),
          dayjs().date(),
          23,
          59,
          59,
        );
      }
      return maxDate;
    });

    onMounted(() => {
      nextTick(() => {
        //回填日期时间值
        inputDateTime.value = mappingProps.modelValue
          ? calDateTime(mappingProps.modelValue)
          : '';
        if (
          typeof mappingProps.modelValue === 'object' &&
          mappingProps.modelValue !== null
        ) {
          dateTime.value = calDateTime(
            mappingProps.modelValue,
            mappingProps.dateType == 'time'
              ? 'HH:mm:ss'
              : 'YYYY/MM/DD HH:mm:ss',
          );
        } else {
          dateTime.value = mappingProps.modelValue;
        }
      });
    });
    //日期范围检查
    function checkDate(dateStr) {
      const date = dayjs(dateStr);
      // 根据提供的 mappingProps 解析最小和最大日期
      const minDate = dayjs(
        mappingProps.minDate ? mappingProps.minDate : '',
        'YYYY/MM/DD',
      );
      const maxDate = dayjs(
        mappingProps.maxDate ? mappingProps.maxDate : '',
        'YYYY/MM/DD',
      );

      if (minDate.isValid()) {
        if (!maxDate.isValid() || !minDate.isSameOrBefore(maxDate)) {
          // 如果 maxDate 无效或 minDate 不早于 maxDate，则仅检查 date 是否大于 minDate
          return date.isSameOrAfter(minDate);
        } else {
          // 如果 minDate 和 maxDate 都有效且 minDate 早于 maxDate，则检查 date 是否在范围内
          return date.isBetween(minDate, maxDate, null, '[)');
        }
      } else if (maxDate.isValid()) {
        // 如果 minDate 无效而 maxDate 有效，则仅检查 date 是否小于 maxDate
        return date.isSameOrBefore(maxDate);
      }
      return false;
    }
    function closeDateTime() {
      popupVisible.value = false;
      stopEmit = false;
    }

    //确定保存日期
    function saveDateTime() {
      const data = dateTime.value;
      let inputDate =
        mappingProps.dateType === 'time'
          ? new Date().toLocaleDateString() + ' ' + data
          : data;
      inputDateTime.value = inputDate ? calDateTime(inputDate) : '';
      popupVisible.value = false;
      //保存时更新父级绑定值
      emit('update:modelValue', data ? data : '');
    }

    function tmConfirm(data) {
      dateTime.value = data;
      inputDateTime.value = data ? calDateTime(data) : '';
      let value =
        mappingProps.dateType === 'datetime'
          ? dayjs(data).format('YYYY/MM/DD HH:mm:ss')
          : mappingProps.dateType === 'date'
            ? dayjs(data.split(' ')[0]).format('YYYY/MM/DD')
            : data.split(' ')[1];
      emit('update:modelValue', value ? value : '');
    }
    //日期时间格式化
    function calDateTime(data, format) {
      let isValidTime = true;

      if (mappingProps.dateType === 'time') {
        isValidTime = dayjs(
          data.indexOf(' ') > -1
            ? data
            : new Date().toLocaleDateString() + ' ' + data,
        ).isValid();
      }

      return (
        dayjs(
          mappingProps.dateType === 'time' && isValidTime
            ? data.indexOf(' ') === -1
              ? new Date().toLocaleDateString() + ' ' + data
              : data
            : data,
        ).format(format ?? dateTimeFormat) ?? ''
      );
    }
    //日期时间反格式化
    function parseDateTime(data, format) {
      let isValidTime = dayjs(data, dateTimeFormat, true).isValid();
      if (mappingProps.dateType === 'time' && isValidTime) {
        return (
          dayjs(new Date().toLocaleDateString() + ' ' + data).format(
            'YYYY/MM/DD HH:mm:ss',
          ) ?? ''
        );
      } else {
        let formatData1 =
          mappingProps.dateType === 'time' && data.indexOf(':') < 0
            ? dayjs(
                new Date().toLocaleDateString() + ' ' + parseTimeString(data),
              ).format('YYYY/MM/DD HH:mm:ss')
            : dayjs(data, dateTimeFormat).format();
        let formatData2 = dayjs(data).format();
        let formatData3 = dayjs(data).format(dateTimeFormat);
        return dayjs(formatData1).isValid()
          ? formatData1
          : dayjs(formatData2).isValid()
            ? formatData2
            : dayjs(formatData3).isValid()
              ? formatData3
              : '';
      }
    }
    function parseTimeString(timeStr) {
      // 检查字符串长度，确保它是6位
      if (timeStr.length !== 6 && timeStr.length !== 4) {
        throw new Error(
          'Invalid time string. It should be in the format of HHMMSS.',
        );
      }
      // 分割字符串
      const parts = timeStr.split('');

      // 构建时间格式
      const hours = parts.slice(0, 2).join('');
      const minutes = parts.slice(2, 4).join('');
      const seconds = timeStr.length === 6 ? parts.slice(4, 6).join('') : '00';

      // 返回格式化的时间字符串
      return `${hours}:${minutes}:${seconds}`;
    }
    let inputFocus = false;
    function inputKeyDown() {
      if (inputFocus && event && event.key === 'Enter') {
        event.preventDefault(); // 阻止默认行为
        if (mappingProps.readonly || mappingProps.disable) {
          return;
        }
        if ($q.screen.xs || $q.platform.is.mobile) {
          showTmPicker();
        } else {
          showPopup();
        }
      }
    }
    function focusShow(evt) {
      inputFocus = true;
    }
    //手动控制弹窗显隐
    function showPopup() {
      popupVisible.value = true;
    }
    let stopEmit = false;
    function showTmPicker() {
      if ($q.screen.xs || $q.platform.is.mobile) {
        let time =
          mappingProps.dateType == 'time'
            ? mappingProps.modelValue
            : dayjs(mappingProps.modelValue).isValid()
              ? dayjs(mappingProps.modelValue).format('YYYY/MM/DD HH:mm:ss')
              : '';
        tmDateTime.value = time;
        refPicker.value.trigger();
      } else {
        popupVisible.value = true;
        stopEmit = true;
      }
    }
    function popShow() {
      if (!inputDateTime.value && !dateTime.value) {
        dateTime.value = dayjs(new Date()).format(
          mappingProps.dateType == 'time' ? 'HH:mm:ss' : 'YYYY/MM/DD HH:mm:ss',
        );
      }
      if (mappingProps.todayBtn) {
        let target = document.querySelector('.q-date__header-title .q-btn');
        if (target) {
          target.title = $q.lang.dateTime.today;
        }
      }
      if (mappingProps.nowBtn) {
        let target = document.querySelector('.q-time__content .q-btn');
        if (target) {
          target.title = $q.lang.dateTime.current;
        }
      }
    }
    //onBlur
    function formatValue() {
      inputFocus = false;
      if (inputDateTime.value && inputDateTime.value !== 'Invalid Date') {
        let isValid =
          inputCheck(inputDateTime.value) && rangeCheck(inputDateTime.value);
        if (isValid) {
          let input = parseDateTime(inputDateTime.value);
          dateTime.value = calDateTime(
            input,
            mappingProps.dateType == 'time'
              ? 'HH:mm:ss'
              : mappingProps.dateType == 'datetime'
                ? 'YYYY/MM/DD HH:mm:ss'
                : 'YYYY/MM/DD',
          );
          inputDateTime.value = calDateTime(input);
          if (stopEmit) {
            //点击图标打开时间选择时会自动触发一次focus和blur，阻止这种行为带来的数据变化通知
            stopEmit = false;
            return;
          }
          emit('update:modelValue', dateTime.value ? dateTime.value : '');
        }
      } else {
        emit('update:modelValue', '');
      }
    }
    //时间格式校验
    function inputCheck(val) {
      if (val) {
        let isValid = dayjs(val).isValid();
        let isValidFormat = dayjs(val, dateTimeFormat, true).isValid();
        return isValid || isValidFormat;
      } else {
        return true;
      }
    }
    //时间范围校验
    function rangeCheck(val) {
      if (
        (!mappingProps.minDate && !mappingProps.maxDate) ||
        mappingProps.dateType === 'time' ||
        !val
      ) {
        return true;
      }
      const isValid = inputCheck(val);
      if (!isValid) {
        return false;
      }
      const parseDate = parseDateTime(val);
      const date = dayjs(parseDate).format('YYYY/MM/DD');
      let result = checkDate(date);
      return result;
    }
    function clearFunction(value) {
      emit('update:modelValue', '');
    }
    function valueUpdate(value) {
      emit('change', value);
    }
    function clickFunction() {
      if ($q.screen.xs || $q.platform.is.mobile) {
        if (mappingProps.readonly || mappingProps.disable) {
          return;
        }
        showTmPicker();
        refInput.value.blur();
      }
    }
    return () => {
      return (
        <div class={'no-outline'}>
          <TmDateTimePicker
            ref={refPicker}
            hideLabel={true}
            hideCell={true}
            dateType={mappingProps.dateType}
            v-model={tmDateTime.value}
            confirmButtonText={
              mappingProps.confirmButtonText
                ? mappingProps.confirmButtonText
                : $q.lang.dateTime?.confirm
            }
            cancelButtonText={
              mappingProps.cancelButtonText
                ? mappingProps.cancelButtonText
                : $q.lang.dateTime?.cancel
            }
            onUpdate:modelValue={tmConfirm}
            minDate={mobileMinDate.value}
            maxDate={mobileMaxDate.value}
          ></TmDateTimePicker>
          <Input
            ref={refInput}
            class={[
              'tr-date-time',
              'tr-input-form',
              styles.module,
              'no-outline',
            ]}
            {...pickOwnForBasicComponent(mappingProps, Input.props, attrs)}
            placeholder={mappingProps.placeholder}
            debounce={300}
            v-model={inputDateTime.value}
            clearable={true}
            onFocus={focusShow}
            onBlur={formatValue}
            onKeydown={inputKeyDown}
            rules={
              mappingProps.rules
                ? [
                    ...mappingProps.rules,
                    val => inputCheck(val) || $q.lang.dateTime?.InvalidDate,
                    val => rangeCheck(val) || $q.lang.dateTime?.OutRange,
                  ]
                : [
                    val => inputCheck(val) || $q.lang.dateTime?.InvalidDate,
                    val => rangeCheck(val) || $q.lang.dateTime?.OutRange,
                  ]
            }
            lazy-rules={true}
            onClear={clearFunction}
            onClick={clickFunction}
          >
            {{
              append: () => {
                return (
                  <Icon
                    name={
                      mappingProps.dateType == 'time' ? 'access_time' : 'event'
                    }
                    class='cursor-pointer no-outline'
                    v-show={!mappingProps.disable && !mappingProps.readonly}
                    tabIndex='-1'
                    onClick={showTmPicker}
                  >
                    {$q.screen.xs || $q.platform.is.mobile ? (
                      ''
                    ) : (
                      <PopupProxy
                        v-model={popupVisible.value}
                        no-parent-event
                        onShow={popShow}
                        transition-show='scale'
                        transition-hide='scale'
                        class={styles.datetimepopup}
                        cover={$q.screen.xs || $q.platform.is.mobile}
                      >
                        <div
                          class={[
                            'date-time-section',
                            ($q.screen.xs || $q.platform.is.mobile) &&
                              'isMobile',
                          ]}
                        >
                          {mappingProps.dateType == 'datetime' ||
                          mappingProps.dateType == 'date' ? (
                            <DateComponent
                              ref={refDate}
                              v-show={mappingProps.visible}
                              // mask={mask.value} //这样设置后返回值也会变成mask要求的格式，处理“年月日时不好处理”暂时隐藏
                              mask={
                                mappingProps.dateType == 'date'
                                  ? 'YYYY/MM/DD'
                                  : 'YYYY/MM/DD HH:mm:ss'
                              }
                              v-model={dateTime.value}
                              today-btn={mappingProps.todayBtn}
                              navigation-min-year-month='1000/01'
                              // range={mappingProps.range} //暂不支持
                              options={optionsFn}
                            ></DateComponent>
                          ) : (
                            ''
                          )}
                          {mappingProps.dateType == 'datetime' ||
                          mappingProps.dateType == 'time' ? (
                            <TimeComponent
                              ref={refTime}
                              mask={
                                mappingProps.dateType == 'time'
                                  ? 'HH:mm:ss'
                                  : 'YYYY/MM/DD HH:mm:ss'
                              }
                              v-model={dateTime.value}
                              format24h={mappingProps.format24h}
                              with-seconds={mappingProps.withSeconds}
                              now-btn={mappingProps.nowBtn}
                              hour-options={mappingProps.hourOptions}
                              minute-options={mappingProps.minuteOptions}
                              second-options={mappingProps.secondOptions}
                            ></TimeComponent>
                          ) : (
                            ''
                          )}
                        </div>
                        <div class='date-time-dateaction'>
                          <div class='date-time-actions'>
                            <Button
                              label={
                                mappingProps.cancelButtonText
                                  ? mappingProps.cancelButtonText
                                  : $q.lang.dateTime?.cancel
                              }
                              class='tr-button-default'
                              v-close-popup
                              onClick={closeDateTime}
                              tabIndex='0'
                            />
                          </div>
                          <Button
                            label={
                              mappingProps.confirmButtonText
                                ? mappingProps.confirmButtonText
                                : $q.lang.dateTime?.confirm
                            }
                            class='tr-button-primary'
                            onClick={saveDateTime}
                            v-close-popup
                            tabIndex='0'
                          />
                        </div>
                      </PopupProxy>
                    )}
                  </Icon>
                );
              },
            }}
          </Input>
        </div>
      );
    };
  },
});
